#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   应用层时序参数测试_app_test.py
@Time    :   2025/03/20 13:31:28
@Author  :   YangLiang 
@Version :   1.0
@Contact :   yangl@genvict.com
@License :   (C)Copyright 2022-2025
@Desc    :   应用层时序参数测试APP
'''

from pandas._libs import interval
import pytest
import allure
import time
from pytest_assume.plugin import assume
import Set_up
from commDriver.TS_CAN import *
import math

uds_stuffing_byte = [0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA]

class Test_ApplicationLayer_APP:
    
    @allure.severity('critical')
    @allure.title('监控应用程序中的从接收到请求报文到开始发送应答报文之间的时间间隔P2server')
    @allure.description('监控应用程序中从接收到请求报文到开始发送应答报文之间的时间间隔P2server,是否在P2server的范围内')
    def test_app_P2server_time(self, action, Driver):
        """
        测试应用层从接收到请求报文到开始发送应答报文之间的时间间隔P2server
        Args:
            action: 测试动作对象
            Driver: 包含CAN驱动的测试驱动对象
        """
        iStep = 1
        # 切换为APP
        iStep, uds_resp, respTime = Driver['CAN'].Send_And_Receive(Driver, "02 10 01", iStep)
        with allure.step(f"第{iStep}步:判断切换APP返回是否正确 # 50 01"):
            assert uds_resp[0:3] == [0x06, 0x50, 0x01], logging.error(f"切换APP失败,返回值为{uds_resp}")
            iStep += 1
        with allure.step(f"第{iStep}步:判断P2server时间是否在范围内 # <50ms"):
            assert respTime < 50, logging.error(f"P2server时间为{respTime}ms,不在50ms范围内")
            iStep += 1
        # 正响应
        iStep, uds_resp, respTime = Driver['CAN'].Send_And_Receive(Driver, "02 10 01", iStep)
        with allure.step(f"第{iStep}步:判断是否正响应 # 06 50 01"):
            with assume:
                assert uds_resp[0:3] == [0x06, 0x50, 0x01], logging.error(f"正响应失败,返回值为{uds_resp}")
        with allure.step(f"第{iStep}步:判断P2server时间是否在范围内 # <50ms"):
            assert respTime < 50, logging.error(f"P2server时间为{respTime}ms,不在50ms范围内")
            iStep += 1
        # 负响应
        iStep, uds_resp, respTime = Driver['CAN'].Send_And_Receive(Driver, "02 10 0A", iStep)
        with allure.step(f"第{iStep}步:判断是否负响应 # 03 7F 10 12"):
            with assume:
                assert uds_resp[0:4] == [0x03, 0x7F, 0x10, 0x12], logging.error(f"负响应失败,返回值为{uds_resp}")
        with allure.step(f"第{iStep}步:判断P2server时间是否在范围内 # <50ms"):
            assert respTime < 50, logging.error(f"P2server时间为{respTime}ms,不在50ms范围内")
            iStep += 1
        # 多帧响应
        iStep, uds_resp, respTime = Driver['CAN'].Send_And_Receive(Driver, "03 22 F1 90", iStep)
        with allure.step(f"第{iStep}步:判断是否多帧响应 # 10 14 62"):
            with assume:
                assert uds_resp[0:3] == [0x10, 0x14, 0x62], logging.error(f"多帧响应失败,返回值为{uds_resp}")
        with allure.step(f"第{iStep}步:判断P2server时间是否在范围内 # <50ms"):
            assert respTime < 50, logging.error(f"P2server时间为{respTime}ms,不在50ms范围内")
            iStep += 1




    @allure.severity('critical')
    @allure.title('检查电控单元在收到诊断请求报文后保持运行在非默认会话的持续时间S3server')
    @allure.description('检查电控单元在收到诊断请求报文后保持运行在非默认会话的持续时间S3server,是否在S3server的范围内')
    def test_app_S3server_time(self, action, Driver):
        """
        测试应用层在收到诊断请求报文后保持运行在非默认会话的持续时间S3server
        Args:
            action: 测试动作对象
            Driver: 包含CAN驱动的测试驱动对象
        """
        iStep = 1
        # 步骤1：进入扩展会话
        iStep, _, _ = Driver['CAN'].checkReqResp(Driver, "10 03", "50 03", 0, iStep, False, 'UDS')
        # 步骤2：发送诊断请求报文
        iStep, _, _ = Driver['CAN'].checkReqResp(Driver, "27 01", "67 01", 0, iStep, False, 'UDS')
        # 等待4.5s S3server内
        time.sleep(4.5)
        logging.info("等待4.5s,S3server内")
        # 步骤3：发送诊断请求报文
        iStep, _, _ = Driver['CAN'].checkReqResp(Driver, "27 01", "67 01", 0, iStep, False, 'UDS')
        # 等待5.5s S3server外
        time.sleep(5.5) 
        logging.info("等待5.5s,S3server外")
        # 步骤4：发送诊断请求报文
        iStep, _, _ = Driver['CAN'].checkReqResp(Driver, "27 01", "7F 27 7F", 0, iStep, False, 'UDS')

    @allure.severity('critical')
    @allure.title('检查电控单元在收到诊断请求后，填充位应该是0xaa')
    @allure.description('检查电控单元在收到诊断请求后，填充位应该是0xaa')
    def test_app_stuffing_byte(self, action, Driver):
        """
        测试UDS传输层位填充功能的有效性
        Args:
            action: 测试动作对象
            Driver: 包含CAN驱动的测试驱动对象
        验证UDS响应中的位填充字节是否符合预期值0xaa
        """
        iStep = 1
        step, uds_resp, size = Driver['CAN'].checkReqResp(Driver, "10 01", "50 01 00 32 01 F4", 0, iStep, False)
        time.sleep(1)
        iStep, uds_resp, _ = Driver['CAN'].Send_And_Receive(Driver, "02 10 03", iStep)
        # 计算所有数据的长度（UDS首帧格式：PCI高4位为0x1，低4位+第二个字节为总长度）
        data_length = ((uds_resp[0] & 0x0F) << 8) | uds_resp[1]
        # 计算总帧数：首帧已包含6字节数据，后续每帧最多7字节
        
        frame_count = 1 if data_length <= 6 else math.ceil((data_length - 6) / 7) + 1
        # 计算总长度：数据长度 + 帧计数(每个帧1字节PCI) + 2字节首帧PCI
        total_length = data_length + frame_count - 1 + 2
        
        if uds_resp:
            # 获取所有的填充位
            stuffing_bytes = uds_resp[total_length:]
            with assume: assert stuffing_bytes == uds_stuffing_byte[:len(stuffing_bytes)],logging.error(f"位填充异常,实际值：{stuffing_bytes.hex()}, 预期值：{uds_stuffing_byte[:len(stuffing_bytes)].hex()}")
        else:
            logging.error("未接收到响应报文")
            assert False